package com.yyx.proxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;


public class ProxyUtil {

    /**
     *  content --->string
     *  .java  io
     * .class
     * .new   反射----》class
     * @return
     */
    public static Object newInstance(Object target,ProxyInvocationHandler handler) throws Throwable {
        Object proxy=null;
        //获得接口
        Class targetInf = target.getClass().getInterfaces()[0];
        String infName = targetInf.getSimpleName();

        Class handlerInf = handler.getClass();
        String handlerName = handlerInf.getSimpleName();

        Method methods[] =targetInf.getDeclaredMethods();
        String line="\n";
        String tab ="\t";
        String content ="";

        //包名 package com.sun.dao;
        String packageContent = "package com.sun;"+line;

        //导入 import com.yyx.dao.TestDao;
        //导入 import com.yyx.proxy.ProxyInvocationHandler;
        //导入 import java.lang.reflect.Method;
        String importContent = "import "+targetInf.getName()+";"+line+
                "import "+handlerInf.getName()+";"+line+
                "import java.lang.reflect.Method;"+line;

        //public class $Proxy implements TestDao{
        String clazzFirstLineContent = "public class $Proxy implements "+infName+"{"+line;

        //	private ProxyInvocationHandler target;
        String filedContent  =tab+"private "+handlerName+ " target"+";"+line;

        //public $Proxy (ProxyInvocationHandler target){
        String constructorContent =tab+"public $Proxy ("+handlerName+" target){" +line
                                  +tab+tab+"this.target =target;"
                                  +line+tab+"}"+line;
        String methodContent = "";

        //重写所有方法
        for (Method method : methods) {
            String returnTypeName = method.getReturnType().getSimpleName();
            String methodName =method.getName();
            // Sting.class String.class
            Class args[] = method.getParameterTypes();
            String argsContent = "";
            String paramsContent="";
            String parameterTypesContent="";
            int flag =0;
            for (Class arg : args) {
                String temp = arg.getSimpleName();
                //String
                //String p0,Sting p1,
                //String.class,int class
                argsContent+=temp+" p"+flag+",";
                paramsContent+="p"+flag+",";
                parameterTypesContent+=arg.getName()+".class"+",";
                flag++;
            }
            if (argsContent.length()>0){
                argsContent=argsContent.substring(0,argsContent.lastIndexOf(","));
                paramsContent=paramsContent.substring(0,paramsContent.lastIndexOf(","));
                parameterTypesContent=","+parameterTypesContent.substring(0,parameterTypesContent.lastIndexOf(","));
            }

            //public void query(String p0,Sting p1)  {
            methodContent+=tab+"public "+returnTypeName+" "+methodName+"("+argsContent+") {"+line
                    //  Method method = null;
                    // try {
                    +tab+tab+"Method method = null;"+line
                    +tab+tab+" try {"+line

                    //	method = Class.forName("com.yyx.dao.TestDao").getDeclaredMethod("query",int.class);
                    //	Object[] args={p};
                    //	target.invoke(method,args);
                    //} catch (Exception e) {
                    //			e.printStackTrace();
                    //		} catch (Throwable throwable) {
                    //			throwable.printStackTrace();
                    //		}
                    //	}
                    +tab+tab+"method = Class.forName(\""+targetInf.getName()+ "\").getDeclaredMethod(\""+methodName+"\""+parameterTypesContent+");"+line
                    +tab+tab+"Object[]"+" args={"+paramsContent+"};" +line
                    +tab+tab+"target.invoke(method,args);"+line
                    +tab+tab+"} catch (Exception e) {"+line
                    +tab+tab+tab+"e.printStackTrace();"+line
                    +tab+tab+"} catch (Throwable throwable) {"+line
                    +tab+tab+tab+"throwable.printStackTrace();"+line
                    +tab+tab+"}"+line
                    +tab+"}"+line;
        }

        content=packageContent+importContent+clazzFirstLineContent+filedContent+constructorContent+methodContent+"}";

        File file =new File("d:\\com\\sun\\$Proxy.java");
        try {
            if (!file.exists()) {
                file.createNewFile();
            }

            FileWriter fw = new FileWriter(file);
            fw.write(content);
            fw.flush();
            fw.close();


            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
            Iterable units = fileMgr.getJavaFileObjects(file);

            JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
            t.call();
            fileMgr.close();

            URL[] urls = new URL[]{new URL("file:D:\\\\")};
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class clazz = urlClassLoader.loadClass("com.sun.$Proxy");

            Constructor constructor = clazz.getConstructor(handlerInf);

            proxy = constructor.newInstance(handler);
            //clazz.newInstance();
            //Class.forName()
        }catch (Exception e){
            e.printStackTrace();
        }
        return proxy;
    }
}
